#include "24cxx.h"



#if USE_SOFTWARE_I2C==1

void __24CXX_SDA_Set()
{
	HAL_GPIO_WritePin(AT24CXX_SDA_GPIO_PORT, AT24CXX_SDA_GPIO_PIN, GPIO_PIN_SET);
}

void __24CXX_SDA_Reset()
{
	HAL_GPIO_WritePin(AT24CXX_SDA_GPIO_PORT, AT24CXX_SDA_GPIO_PIN, GPIO_PIN_RESET);
}

void __24CXX_SCL_Set()
{
	HAL_GPIO_WritePin(AT24CXX_SCL_GPIO_PORT, AT24CXX_SCL_GPIO_PIN, GPIO_PIN_SET);
}

void __24CXX_SCL_Reset()
{
	HAL_GPIO_WritePin(AT24CXX_SCL_GPIO_PORT, AT24CXX_SCL_GPIO_PIN, GPIO_PIN_RESET);
}



void __24CXX_i2c_delay(void)
{
	uint8_t i=AT24CXX_I2C_DELAY;
	while(i--);
}

void __24CXX_i2c_start(void)
{
/*    _____
 *SDA      \_____________
 *    __________
 *SCL           \________
 */
	__24CXX_SDA_Set();
	__24CXX_SCL_Set();
	__24CXX_i2c_delay();
	__24CXX_SDA_Reset();
	__24CXX_i2c_delay();
	__24CXX_SCL_Reset();
	__24CXX_i2c_delay();
}

void __24CXX_i2c_stop(void)
{
/*               _______
 *SDA __________/
 *          ____________
 *SCL _____/
 */
	__24CXX_SDA_Reset();
	__24CXX_SCL_Set();
	__24CXX_i2c_delay();
	__24CXX_SDA_Set();
}

uint8_t __24CXX_i2c_waitACK(void)
{
	uint32_t timeout=0;
	__24CXX_SDA_Set();
	__24CXX_i2c_delay();
	__24CXX_SCL_Set();
	__24CXX_i2c_delay();
	while(HAL_GPIO_ReadPin(AT24CXX_SDA_GPIO_PORT, AT24CXX_SDA_GPIO_PIN))
	{
		timeout++;
		if(timeout>AT24CXX_I2C_TIMEOUT) return 1;
	}
	__24CXX_SCL_Reset();
	__24CXX_i2c_delay();
	return 0;
}

void __24CXX_i2c_sendACK(void)
{
    /*
     *    ____         _____
     *SDA     \_______/
     *           ____
     *SCL ______/    \______

     */
	__24CXX_SDA_Reset();
	__24CXX_i2c_delay();
	__24CXX_SCL_Set();
	__24CXX_i2c_delay();
	__24CXX_SCL_Reset();
	__24CXX_i2c_delay();
	__24CXX_SDA_Set();
}

void __24CXX_i2c_sendNACK(void)
{
/*
 *    __________________
 *SDA
 *           ____
 *SCL ______/    \______

 */
	__24CXX_SDA_Set();
	__24CXX_i2c_delay();
	__24CXX_SCL_Set();
	__24CXX_i2c_delay();
	__24CXX_SCL_Reset();
	__24CXX_i2c_delay();
}


void __24CXX_i2c_SendByte(uint8_t data)
{
	for(int i=0;i<8;i++)
	{
		if(data&0x80)
		{
			__24CXX_SDA_Set();
		}else {
			__24CXX_SDA_Reset();
		}
		__24CXX_i2c_delay();
		__24CXX_SCL_Set();
		__24CXX_i2c_delay();
		__24CXX_SCL_Reset();
		if(i==7)
		{
			__24CXX_SDA_Set();
		}
		data<<=1;
		__24CXX_i2c_delay();
	}
}

uint8_t __24CXX_i2c_ReadByte(void)
{
	uint8_t data;
	for(int i=0;i<8;i++)
	{
		data<<=1;
		__24CXX_SCL_Set();
		__24CXX_i2c_delay();
		if(HAL_GPIO_ReadPin(AT24CXX_SDA_GPIO_PORT, AT24CXX_SDA_GPIO_PIN)) data++;
		__24CXX_SCL_Reset();
		__24CXX_i2c_delay();
	}
	return data;
}


#endif


uint8_t AT24CXX_WriteData(uint16_t MemAddress,uint8_t *data,int size)
{
	int count=size,writeaddr=MemAddress,res=HAL_OK;
	uint8_t *pdata=data;
	if(MemAddress>AT24CXX_TYPE) return 1;
#if USE_SOFTWARE_I2C==1
	__24CXX_i2c_start();
	if(AT24CXX_TYPE>AT24C16)
	{
		__24CXX_i2c_SendByte(AT24CXX_ADDR);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
		__24CXX_i2c_SendByte(MemAddress>>8);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
		__24CXX_i2c_SendByte(MemAddress);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
	}else {
		__24CXX_i2c_SendByte(AT24CXX_ADDR);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
		__24CXX_i2c_SendByte(MemAddress);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
	}

	while(count)
	{
		__24CXX_i2c_SendByte(*pdata);
		pdata++;
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
		writeaddr++;
		if(writeaddr%AT24CXX_PAGE_SIZE==0&&count>1)
		{
			__24CXX_i2c_stop();
			HAL_Delay(10);
			__24CXX_i2c_start();
			if(AT24CXX_TYPE>AT24C16)
			{
				__24CXX_i2c_SendByte(AT24CXX_ADDR);
				if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
				__24CXX_i2c_SendByte(writeaddr>>8);
				if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
				__24CXX_i2c_SendByte(writeaddr);
				if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
			}else {
				__24CXX_i2c_SendByte(AT24CXX_ADDR);
				if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
				__24CXX_i2c_SendByte(writeaddr);
				if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
			}
		}
		count--;
	}
	__24CXX_i2c_stop();
	HAL_Delay(10);
	return res;
#else
	int selectPage_idx  = writeaddr % AT24CXX_PAGE_SIZE;
	int selectPage_rest = AT24CXX_PAGE_SIZE - selectPage_idx;
	if(AT24CXX_TYPE>AT24C16)
	{
		if (count <= selectPage_rest)
		{
			res = HAL_I2C_Mem_Write(&AT24CXX_I2C_HANDLE,AT24CXX_ADDR,writeaddr,I2C_MEMADD_SIZE_16BIT,pdata,count,0xFF);
			if (HAL_OK != res) { return 1; }
			HAL_Delay(10);
		} else {
			/*! 1 write selectPage rest*/
			res = HAL_I2C_Mem_Write(&AT24CXX_I2C_HANDLE,AT24CXX_ADDR,writeaddr,I2C_MEMADD_SIZE_16BIT,pdata,selectPage_rest,0xFF);
			if (HAL_OK != res) { return 1; }
			writeaddr+= selectPage_rest;
			count	 -= selectPage_rest;
			pdata	 += selectPage_rest;
			HAL_Delay(10);
			/*! 2 write nextPage full */
			int fullPage = count/AT24CXX_PAGE_SIZE;
			for (int iPage = 0; iPage < fullPage; ++iPage)
			{
				res = HAL_I2C_Mem_Write(&AT24CXX_I2C_HANDLE,AT24CXX_ADDR,writeaddr,I2C_MEMADD_SIZE_16BIT,pdata,AT24CXX_PAGE_SIZE,0xFF);
				if (HAL_OK != res) { return 1; }
				HAL_Delay(10);
				writeaddr   += AT24CXX_PAGE_SIZE;
				count 		-= AT24CXX_PAGE_SIZE;
				pdata 		+= AT24CXX_PAGE_SIZE;
			}
			/*! 3 write rest */
			if (0 != count)
			{
				res = HAL_I2C_Mem_Write(&AT24CXX_I2C_HANDLE,AT24CXX_ADDR,writeaddr,I2C_MEMADD_SIZE_16BIT,pdata,count,0xFF);
				if (HAL_OK != res) { return 1; }
				HAL_Delay(10);
			}
		}
		return res;
	}else {
		if (count <= selectPage_rest)
		{
			res = HAL_I2C_Mem_Write(&AT24CXX_I2C_HANDLE,AT24CXX_ADDR,writeaddr,I2C_MEMADD_SIZE_8BIT,pdata,count,0xFF);
			if (HAL_OK != res) { return 1; }
			HAL_Delay(10);
		} else {
			/*! 1 write selectPage rest*/
			res = HAL_I2C_Mem_Write(&AT24CXX_I2C_HANDLE,AT24CXX_ADDR,writeaddr,I2C_MEMADD_SIZE_8BIT,pdata,selectPage_rest,0xFF);
			if (HAL_OK != res) { return 1; }
			writeaddr+= selectPage_rest;
			count	 -= selectPage_rest;
			pdata	 += selectPage_rest;
			HAL_Delay(10);
			/*! 2 write nextPage full */
			int fullPage = count/AT24CXX_PAGE_SIZE;
			for (int iPage = 0; iPage < fullPage; ++iPage)
			{
				res = HAL_I2C_Mem_Write(&AT24CXX_I2C_HANDLE,AT24CXX_ADDR,writeaddr,I2C_MEMADD_SIZE_8BIT,pdata,AT24CXX_PAGE_SIZE,0xFF);
				if (HAL_OK != res) { return 1; }
				HAL_Delay(10);
				writeaddr   += AT24CXX_PAGE_SIZE;
				count 		-= AT24CXX_PAGE_SIZE;
				pdata 		+= AT24CXX_PAGE_SIZE;
			}
			/*! 3 write rest */
			if (0 != count)
			{
				res = HAL_I2C_Mem_Write(&AT24CXX_I2C_HANDLE,AT24CXX_ADDR,writeaddr,I2C_MEMADD_SIZE_8BIT,pdata,count,0xFF);
				if (HAL_OK != res) { return 1; }
				HAL_Delay(10);
			}
		}
	}
	return res;
#endif





}


uint8_t AT24CXX_ReadData(uint16_t MemAddress,uint8_t *buff,int size)
{
	int count=size,res=HAL_OK;
	uint8_t *pdata=buff;
	if(MemAddress>AT24CXX_TYPE) return 1;
#if USE_SOFTWARE_I2C==1
	__24CXX_i2c_start();
	if(AT24CXX_TYPE>AT24C16)
	{
		__24CXX_i2c_SendByte(AT24CXX_ADDR);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
		__24CXX_i2c_SendByte(MemAddress>>8);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
		__24CXX_i2c_SendByte(MemAddress);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
	}else {
		__24CXX_i2c_SendByte(AT24CXX_ADDR);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
		__24CXX_i2c_SendByte(MemAddress);
		if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
	}
	__24CXX_i2c_start();
	__24CXX_i2c_SendByte(AT24CXX_ADDR+1);
	if(__24CXX_i2c_waitACK()==1) return 1;//no ACK
	while(count)
	{
		*pdata++=__24CXX_i2c_ReadByte();
		if(count>1)
		{
			__24CXX_i2c_sendACK();
		}else {
			__24CXX_i2c_sendNACK();
		}
		count--;
	}
	__24CXX_i2c_stop();
	return res;
#else
	if(AT24CXX_TYPE>AT24C16)
	{
		res = HAL_I2C_Mem_Read(&AT24CXX_I2C_HANDLE, AT24CXX_ADDR, MemAddress, I2C_MEMADD_SIZE_16BIT, pdata, count, 0xFF);
		return res;
	}else {
		res = HAL_I2C_Mem_Read(&AT24CXX_I2C_HANDLE, AT24CXX_ADDR, MemAddress, I2C_MEMADD_SIZE_8BIT, pdata, count, 0xFF);
		return res;
	}
#endif

}




uint8_t AT24CXX_Test()
{
	uint8_t data_w[AT24CXX_PAGE_SIZE+1];
	uint8_t data_r[AT24CXX_PAGE_SIZE+1];

	uint8_t random_num=(HAL_GetTick()&0x0f);
	printf("AT24CXX Testing random_num=%u\r\n",random_num);

	for(int i=0;i<AT24CXX_PAGE_SIZE+1;i++)
	{
		data_w[i]=i+random_num;
	}

	for(int i=0;i<AT24CXX_TYPE;i+=128)
	{
		AT24CXX_WriteData(i,data_w,AT24CXX_PAGE_SIZE+1);
		for(int i=0;i<AT24CXX_PAGE_SIZE+1;i++)
		{
			data_r[i]=0;
		}
		AT24CXX_ReadData(i,data_r,AT24CXX_PAGE_SIZE+1);
		SCB_CleanInvalidateDCache();//h7开启Dcache后使用
		for(int i=0;i<AT24CXX_PAGE_SIZE+1;i++)
		{
			if(data_r[i]!=data_w[i])
			{
				printf("AT24CXX Test error : data_w[%d]=%u , data_r[%d]=%u\r\n",i,data_w[i],i,data_r[i]);
				return 1;
			}
		}
		printf("24CXX Capacity : %d Byte\r\n",(i+128));
	}
	return 0;
}











































